#include "session.h"

#include <client.h>
#include <connectionlistener.h>
#include <discohandler.h>
#include <disco.h>
#include <rostermanager.h>
#include <loghandler.h>
#include <logsink.h>
#include <messagehandler.h>
#include <QScopedPointer>

#include <logger/logger.h>
#include <QtCore>

#define LI Opl::Core::LoggerItem()

using namespace gloox;
class SessionPrivate : public RosterListener, ConnectionListener, LogHandler, MessageHandler{
public:
	SessionPrivate() {}
	virtual ~SessionPrivate() {}
	JID jid;
	QScopedPointer<Client> client;

	void start()
	{

		jid = JID( "paskud@gromnica/gloox" );
		client.reset(new Client( jid, "dk2130p" ,5222));
		client->registerConnectionListener( this );
		client->registerMessageHandler( this );
		client->rosterManager()->registerRosterListener( this );
		client->disco()->setVersion( "rosterTest", GLOOX_VERSION );
		client->disco()->setIdentity( "client", "bot" );

		client->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );

		client->connect();

		//delete( j );
	}

	virtual void onConnect()
	{
		LI.Debug() << QString("Connected");
	}
	virtual void onDisconnect( ConnectionError e ) { LI.Debug() << QString( "disco_test: disconnected: %d\n").arg( e ); }

	virtual bool onTLSConnect( const CertInfo& info )
	{
		LI.Debug() << QString( "status: %1\nissuer: %2\npeer: %3\nprotocol: %4\nmac: %5\ncipher: %6\ncompression: %7").arg(
				info.status).arg(info.issuer.c_str(), info.server.c_str(),
								 info.protocol.c_str(), info.mac.c_str(), info.cipher.c_str(),
								 info.compression.c_str());
		return true;
	}

	virtual void onResourceBindError( ResourceBindError error )
	{
		LI.Debug() << QString("onResourceBindError: %1").arg(error);
	}

	virtual void onSessionCreateError( SessionCreateError error )
	{
		LI.Debug() << QString( "onSessionCreateError: %1").arg(error);
	}

	virtual void handleItemSubscribed( const JID& jid )
	{
		LI.Debug() << QString( "subscribed %1").arg( jid.bare().c_str() );
	}

	virtual void handleItemAdded( const JID& jid )
	{
		LI.Debug() << QString( "added %1").arg( jid.bare().c_str() );
	}

	virtual void handleItemUnsubscribed( const JID& jid )
	{
		LI.Debug() << QString( "unsubscribed %1").arg( jid.bare().c_str() );
	}

	virtual void handleItemRemoved( const JID& jid )
	{
		LI.Debug() << QString( "removed %1").arg( jid.bare().c_str() );
	}

	virtual void handleItemUpdated( const JID& jid )
	{
		LI.Debug() << QString( "updated %1").arg( jid.bare().c_str() );
	}

	virtual void handleRoster( const Roster& roster )
	{
		LI.Debug() << QString( "roster arriving\nitems:\n" );
		Roster::const_iterator it = roster.begin();
		for( ; it != roster.end(); ++it )
		{
			LI.Debug() << QString( "jid: %1, name: %2, subscription: %3").arg(
					(*it).second->jid().c_str(), (*it).second->name().c_str()).arg((*it).second->subscription());
			StringList g = (*it).second->groups();
			StringList::const_iterator it_g = g.begin();
			for( ; it_g != g.end(); ++it_g )
				LI.Debug() << QString( "\tgroup: %1").arg( (*it_g).c_str() );
			RosterItem::ResourceMap::const_iterator rit = (*it).second->resources().begin();
			for( ; rit != (*it).second->resources().end(); ++rit )
				LI.Debug() << QString( "resource: %1").arg( (*rit).first.c_str() );
		}
	}

	virtual void handleRosterError( Stanza * /*stanza*/ )
	{
		LI.Debug() << QString( "an roster-related error occured\n" );
	}

	virtual void handleRosterPresence( const RosterItem& item, const std::string& resource,
									   Presence presence, const std::string& /*msg*/ )
	{
		LI.Debug() << QString( "presence received: %1/%2 -- %3").arg( item.jid().c_str(), resource.c_str()).arg(presence );
	}

	virtual void handleSelfPresence( const RosterItem& item, const std::string& resource,
									 Presence presence, const std::string& /*msg*/ )
	{
		LI.Debug() << QString( "self presence received: %1/%2 -- %3").arg( item.jid().c_str(), resource.c_str()).arg(presence );
	}

	virtual bool handleSubscriptionRequest( const JID& jid, const std::string& /*msg*/ )
	{
		LI.Debug() << QString( "subscription: %1").arg( jid.bare().c_str() );
		StringList groups;
		JID id( jid );
		client->rosterManager()->subscribe( id, "", groups, "" );
		return true;
	}

	virtual bool handleUnsubscriptionRequest( const JID& jid, const std::string& /*msg*/ )
	{
		LI.Debug() << QString( "unsubscription: %1").arg( jid.bare().c_str() );
		return true;
	}

	virtual void handleNonrosterPresence( Stanza* stanza )
	{
		LI.Debug() << QString( "received presence from entity not in the roster: %1").arg( stanza->from().full().c_str() );
	}

	virtual void handleLog( LogLevel level, LogArea area, const std::string& message )
	{
		QString logmessage = QString("log: level: %1, area: %2, %3").arg( level).arg(area).arg(message.c_str());
		switch(level)
		{
		case LogLevelDebug:
			LI.Debug() << logmessage;
			break;
		case LogLevelWarning:
			LI.Warning() << logmessage;
			break;
		case LogLevelError:
			LI.Error() << logmessage;
			break;
		}

	}

	virtual void handleMessage( Stanza *stanza, MessageSession * /*session*/ )
	{
		if( stanza->body() == "quit" )
			client->disconnect();
		else if( stanza->body() == "subscribe" )
			client->rosterManager()->subscribe( stanza->from() );
		else if( stanza->body() == "unsubscribe" )
			client->rosterManager()->unsubscribe( stanza->from() );
		else if( stanza->body() == "cancel" )
			client->rosterManager()->cancel( stanza->from() );
		else if( stanza->body() == "remove" )
			client->rosterManager()->remove( stanza->from() );
		else
			LI.Debug() << QString( "msg: %1").arg( stanza->body().c_str() );
	}
};

Session::Session(Opl::Core::EntityObject *parent) :
		Opl::Core::EntityObject(parent), O_PRIVATE_CREATE(Session)
{
	O_D(Session);
	//d->start();
}

Session::~Session()
{
	O_PRIVATE_DELETE;
}
